package com.jeehentor.annotation;

import com.alibaba.fastjson2.JSONObject;
import com.jeehentor.common.api.SystemCommonAPI;
import com.jeehentor.common.api.vo.SystemLog;
import com.jeehentor.utils.ClientIPUtil;
import com.jeehentor.utils.SecurityUtil;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description : 操作日志切面处理类
 * @Author : wzd
 * @Date : 2024/4/30 14:17
 * @Version : 1.0
 **/
@Aspect
@Component
@RequiredArgsConstructor
public class WebLogAspect {
    private final SystemCommonAPI systemCommonApi;
    private long startTime;
    /**
     * 注解的全类名
     */
    @Pointcut("@annotation(com.jeehentor.annotation.SystemLogAnnotation)")
//    @Pointcut("execution(* com.jeehentor.*.controller..*(..)) && !execution(* com.jeehentor.*.controller.test.*.*(..))")
    public void webLogPoinCut() {
    }

    @Before("webLogPoinCut()")
    public void doBefore(JoinPoint joinPoint) {
        startTime = System.currentTimeMillis();
    }

    /**
     * 记录操作日志
     * @param joinPoint 方法的执行点
     * @param result  方法返回值
     * @throws Throwable
     */
    @AfterReturning(returning  = "result", value = "webLogPoinCut()")
    public void saveOptLog(JoinPoint joinPoint, Object result) throws Throwable {
        //判断是否操作成功
        JSONObject jsonObject =  (JSONObject) JSONObject.parseObject(JSONObject.toJSONString(result));
        if(!"200".equals(jsonObject.getString("code"))){
            return;
        }

        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        assert requestAttributes != null;
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {

            SystemLog log = new SystemLog();
            log.setLogType(2);
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取操作
            SystemLogAnnotation annotation = method.getAnnotation(SystemLogAnnotation.class);
            //模块名称
            if (annotation != null) {
                //操作人{optuser}{模块名}{增删改查}{原内容}为{修改内容}
                //操作用户  填自己的
                String content = SecurityUtil.getCurrentUser().getRealname();
                //操作模块和操作说明
                content += "-" + annotation.optModul() + "-" + annotation.optDesc();
                //操作类型
                if(StringUtils.isNotEmpty(annotation.optType())){
                    String optType = getOptType(annotation.optType());
                    content += "-" +optType;
                    log.setOperateType(annotation.optType());
                }
                //内容
                if(StringUtils.isNotEmpty(getAnnotationValue(joinPoint,annotation.optParam()))){
                    content += "-" + getAnnotationValue(joinPoint,annotation.optParam());
                }
                //修改内容
                if(StringUtils.isNotEmpty(getAnnotationValue(joinPoint,annotation.optUpdateParam()))){
                    content += "为" + getAnnotationValue(joinPoint,annotation.optUpdateParam());
                }

                log.setLogContent(content);
            }

            //操作用户  填自己的
            log.setUserid(SecurityUtil.getCurrentUser().getId());
            log.setCreateBy(SecurityUtil.getCurrentUser().getId());
            log.setUsername(SecurityUtil.getCurrentUser().getRealname());
            //客户端真实IP
            assert request != null;
            log.setIp(ClientIPUtil.getClientIP(request));
            log.setMethod(method.getName());
            log.setRequestUrl(request.getRequestURI());
            log.setCostTime(System.currentTimeMillis() - startTime);
            assert annotation != null;
            log.setRequestParam(getAnnotationValue(joinPoint,annotation.optParam()));
            log.setRequestType(request.getMethod());
            //保存日志
            systemCommonApi.saveLog(log);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取注解中传递的动态参数的参数值
     *
     * @param joinPoint
     * @param name
     * @return
     */
    public String getAnnotationValue(JoinPoint joinPoint, String name) {
        String paramName = name;
        // 获取方法中所有的参数
        Map<String, Object> params = getParams(joinPoint);
        // 参数是否是动态的:#{paramName}
        if (paramName.matches("^#\\{\\D*\\}")) {
            // 获取参数名
            paramName = paramName.replace("#{", "").replace("}", "");
            // 是否是复杂的参数类型:对象.参数名
            if (paramName.contains(".")) {
                String[] split = paramName.split("\\.");
                // 获取方法中对象的内容
                Object object = getValue(params, split[0]);
                // 转换为JsonObject
                JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(object));
                // 获取值
                Object o = jsonObject.get(split[1]);

                return String.valueOf(o);
            }
            // 简单的动态参数直接返回
            return String.valueOf(getValue(params, paramName));
        }
        // 非动态参数直接返回
        return name;
    }

    /**
     * 根据参数名返回对应的值
     *
     * @param map
     * @param paramName
     * @return
     */
    public Object getValue(Map<String, Object> map, String paramName) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getKey().equals(paramName)) {
                return entry.getValue();
            }
        }
        return null;
    }


    /**
     * 获取方法的参数名和值
     *
     * @param joinPoint
     * @return
     */
    public Map<String, Object> getParams(JoinPoint joinPoint) {
        Map<String, Object> params = new HashMap<>(8);
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String[] names = signature.getParameterNames();
        for (int i = 0; i < args.length; i++) {
            params.put(names[i], args[i]);
        }
        return params;
    }

    public String getOptType(String methodName){
        if(methodName.startsWith("save") || methodName.startsWith("create")
                || methodName.startsWith("add")
                || methodName.startsWith("insert")){
            return "新增";
        }else if(methodName.startsWith("update") || methodName.startsWith("edit")
                || methodName.startsWith("modify")
                || methodName.startsWith("change")){
            return "修改";
        }else if(methodName.startsWith("del") || methodName.startsWith("remove")
                || methodName.startsWith("delete") || methodName.startsWith("batchDel")){
            return "删除";
        }else if(methodName.startsWith("query") || methodName.startsWith("get")
                || methodName.startsWith("find") || methodName.startsWith("page")
                || methodName.startsWith("select") || methodName.startsWith("list") ){
            return "查询";
        }else {
            return "";
        }
    }

}
